<link rel="import" href="../../bower_components/polymer/polymer-element.html">
<link rel="import" href="../../bower_components/vaadin-material-theme/vaadin-date-picker.html">
<link rel="import" href="../../bower_components/vaadin-material-theme/vaadin-text-field.html">
<link rel="import" href="../../bower_components/vaadin-material-theme/vaadin-combo-box.html">
<link rel="import" href="../../bower_components/paper-item/paper-icon-item.html">
<link rel="import" href="../../bower_components/paper-item/paper-item-body.html">
<link rel="import" href="../../bower_components/paper-item/paper-item.html">
<link rel="import" href="../../lib/jsLPSolver.html">
<link rel="import" href="../view-app.html">
<link rel="import" href="../style/shared-styles.html">

<dom-module id="view-plan-order">
    <template>
        <style include="shared-styles app-grid-style">
            :host {
                margin: 10px;
                display: block;
                --app-grid-item-height: 50%;
            }

            @media (min-width: 360px) and (max-width: 768px) {
                :host {
                    --app-grid-columns: 1;
                }
            }

            @media (min-width: 769px) and (max-width: 1024px) {
                :host {
                    --app-grid-columns: 1;
                }
            }

            @media (min-width: 1025px) and (max-width: 1200px) {
                :host {
                    --app-grid-columns: 2;
                }
            }

            @media (min-width: 1201px) {
                :host {
                    --app-grid-columns: 2;
                }
            }

            #createOrderCard {
                height: 697px;
            }

            .frame {
                padding: 10px;
                width: 33.333%;
                margin: 10px;
            }

            @media print {
                #createOrderCard {
                    display: none;
                }
            }
        </style>
        <firebase-auth app-name="smart-mes" id="auth" user="{{user}}"></firebase-auth>
        <firebase-document app-name="smart-mes" id="userData" path="/user/[[user.uid]]" data="{{k}}"></firebase-document>
        <firebase-document app-name="smart-mes" id="appMaterialCount" path="/data/[[k.key]]/appData/material_count" data="{{materialCount}}"></firebase-document>
        <firebase-document app-name="smart-mes" id="factoryPerformance" path="/data/[[k.key]]/factoryData/performance" data="{{factoryPerformance}}"></firebase-document>
        <firebase-document app-name="smart-mes" id="factoryOperation" path="/data/[[k.key]]/factoryData/operation" data="{{factoryOperation}}"></firebase-document>
        <firebase-document app-name="smart-mes" id="factoryOrderIndex" path="/data/[[k.key]]/factoryData/order" data="{{factoryOrderIndex}}"></firebase-document>
        <firebase-document app-name="smart-mes" id="factoryProfileModel" path="/data/[[k.key]]/factoryData/profile/model" data="{{factoryProfileModel}}"></firebase-document>
        <firebase-query app-name="smart-mes" id="orderQuery" path="/data/[[k.key]]/orderData" data="{{orderItems}}"></firebase-query>
        <firebase-query app-name="smart-mes" id="factoryInventory" path="/data/[[k.key]]/factoryData/inventory" order-by-child="code"
            equal-to="[[inventoryCode]]" data="{{factoryInventory}}"></firebase-query>
        <firebase-query app-name="smart-mes" id="historyQuery" path="/data/[[k.key]]/historyData/order"></firebase-query>
        <firebase-query app-name="smart-mes" id="notificationQuery" path="/data/[[k.key]]/notificationData"></firebase-query>
        <firebase-query app-name="smart-mes" id="customerQuery" path="/data/[[k.key]]/factoryData/customer" order-by-child="fname"
            data="{{customerItems}}"></firebase-query>
        <firebase-query app-name="smart-mes" id="productQuery" path="/data/[[k.key]]/factoryData/product" order-by-child="name" data="{{productItems}}"></firebase-query>
        <firebase-query app-name="smart-mes" id="inventoryQuery" path="/data/[[k.key]]/factoryData/inventory" order-by-child="code"
            data="{{inventoryItems}}"></firebase-query>
        <app-localstorage-document key="app-lang" data="{{language}}"></app-localstorage-document>
        <ul class="app-grid">
            <li>
                <div class="card" id="createOrderCard">
                    <h1 class="title">{{localize('create-order')}}</h1>
                    <vaadin-combo-box label="{{localize('customer-name')}}" name="customer-name" id="customerSelector" items="[[customerItems]]"
                        item-label-path="name" item-value-path="name" selected-item='{{selectCustomer}}' loading="[[!customerItems]]"
                        required allow-custom-value prevent-invalid-input always-float-label>
                        <template>
                            <paper-item>
                                <paper-icon-item style="padding: 0">
                                    <iron-icon icon="vaadin:user-card" slot="item-icon"></iron-icon>
                                    <paper-item-body two-line style="min-height: 0">
                                        <div>[[item.name]]</div>
                                        <div secondary>[[item.email]]</div>
                                    </paper-item-body>
                                </paper-icon-item>
                            </paper-item>
                        </template>
                    </vaadin-combo-box>
                    <vaadin-combo-box label="{{localize('product')}}" name="product" items="[[productItems]]" id="productSelector" item-label-path="name"
                        item-value-path="name" selected-item='{{selectProduct}}' on-change="verifyProductPart" loading="[[!productItems]]"
                        required prevent-invalid-input always-float-label>
                        <template>
                            <paper-icon-item style="padding: 0">
                                <img src$="[[getProductImage(item.image)]]" width="48" height="auto" class="thumbnail" slot="item-icon">
                                <paper-item-body two-line style="min-height: 0">
                                    <div>[[item.name]]</div>
                                    <div secondary>SKU: [[item.sku]]</div>
                                </paper-item-body>
                            </paper-icon-item>
                        </template>
                    </vaadin-combo-box>
                    <vaadin-text-field label="{{localize('quantity')}}" value='{{amount}}' name="order-quantity" id="orderQuantity" error-message="Invalid Input"
                        onkeypress='return event.charCode >= 48 && event.charCode <= 57' required>
                    </vaadin-text-field>
                    <vaadin-date-picker label="{{localize('delivery-date')}}" min="[[todayDate]]" max="2030-01-01" name="delivery" id="deliverySelector"
                        initial-position="[[todayDate]]" value="{{delivery}}" error-message="Invalid input" required always-float-label></vaadin-date-picker>
                    <paper-button on-click="printOrderReport" class="btn" title="Print order report">
                        {{localize('print-order-report')}}
                    </paper-button>
                    <paper-button on-click="createOrder" class="shamrock btn" title="Add order">
                        {{localize('add-to-schedule')}}
                    </paper-button>
                </div>
            </li>
            <li>
                <div class="card" id="detailOrderCard">
                    <h1 class="title">{{localize('order-detail')}}</h1>
                    <ul class="parent">
                        <li class="left">
                            <p>{{localize('order-number')}}</p>
                        </li>
                        <li class="right">
                            <p>[[orderNumber]]</p>
                        </li>
                    </ul>
                    <div class="separator-line" role="separator"></div>
                    <ul class="parent">
                        <li class="left">
                            <p>{{localize('customer-name')}}</p>
                        </li>
                        <li class="right">
                            <p>[[selectCustomer.name]]</p>
                        </li>
                    </ul>
                    <div class="separator-line" role="separator"></div>
                    <ul class="parent">
                        <li class="left">
                            <p>{{localize('product-name')}}</p>
                        </li>
                        <li class="right">
                            <p>[[setProductPart(selectProduct)]]</p>
                        </li>
                    </ul>
                    <div class="separator-line" role="separator"></div>
                    <ul class="parent">
                        <li class="left">
                            <p>{{localize('sku-code')}}</p>
                        </li>
                        <li class="right">
                            <p>[[setProductSKU(selectProduct.sku)]]</p>
                        </li>
                    </ul>
                    <div class="separator-line" role="separator"></div>
                    <ul class="parent">
                        <li class="left">
                            <p>{{localize('product-part')}}</p>
                        </li>
                        <li class="right">
                            <p>
                                <template is="dom-repeat" items="[[selectProduct.part]]" as="productPart">
                                    [[productPart.name]]
                                </template>
                            </p>
                        </li>
                    </ul>
                    <div class="separator-line" role="separator"></div>
                    <ul class="parent">
                        <li class="left">
                            <p>{{localize('actual-quantity')}}</p>
                        </li>
                        <li class="right">
                            <p>[[getActualQuantity(amount)]]</p>
                        </li>
                    </ul>
                    <div class="separator-line" role="separator"></div>
                    <ul class="parent">
                        <li class="left">
                            <p>{{localize('raw-materials-required')}}</p>
                        </li>
                        <li class="right">
                            <p>[[selectProduct.inventory_code]] [[getUseInventory(amount,selectProduct.inventory_use)]]</p>
                        </li>
                    </ul>
                    <div class="separator-line" role="separator"></div>
                    <ul class="parent">
                        <li class="left">
                            <p>{{localize('order-duration')}}</p>
                        </li>
                        <li class="right">
                            <p>[[getSumProductTime(selectProduct.part,amount)]]</p>
                        </li>
                    </ul>
                    <div class="separator-line" role="separator"></div>
                    <ul class="parent">
                        <li class="left">
                            <p>{{localize('delivery-date')}}</p>
                        </li>
                        <li class="right">
                            <p>[[delivery]]</p>
                        </li>
                    </ul>
                    <div class="separator-line" role="separator"></div>
                    <ul class="parent">
                        <li class="left">
                            <p>{{localize('cost')}}</p>
                        </li>
                        <li class="right">
                            <p>[[getProductCost(selectProduct.cost,amount)]]</p>
                        </li>
                    </ul>
                    <div class="separator-line" role="separator" id="optimizeDataSeparate"></div>
                    <ul class="parent" id="optimizeData">
                        <li class="left">
                            <p>{{localize('optimal-quantity')}} / {{localize('week')}}</p>
                        </li>
                        <li class="right">
                            <p>[[getOptimalQuantity(selectProduct.cost, selectProduct.part)]]</p>
                        </li>
                    </ul>
                </div>
            </li>
        </ul>
        <div class="card" id="productFragmentCard">
            <h1 class="title">{{localize('product-fragmentation')}}</h1>
            <div class="flex-container">
                <template is="dom-repeat" items="{{selectProduct.part}}" as="part">
                    <div class="frame frame-small flex-item">
                        <h2 class="title">{{localize('product-part')}} [[part.name]]</h2>
                        <p>{{localize('sku-code')}}: [[part.sku]]</p>
                        <p>{{localize('process-sequence')}}: [[getProductProcessSequence(part.process)]]</p>
                        <p>{{localize('setup-time')}}: [[getSumSetupTime(part.setup)]] seconds</p>
                        <p>{{localize('cycle-time')}}: [[getSumCycleTime(part.cycle)]] seconds</p>
                    </div>
                </template>
            </div>
        </div>
    </template>
    <script>
        /**
         * @ViewPlanOrder
         * @polymer 
         * @extends {Polymer.Element}
         */
        class ViewPlanOrder extends Polymer.mixinBehaviors([Polymer.AppLocalizeBehavior],
            Polymer.Element) {
            static get is() {
                return 'view-plan-order'
            }

            static get properties() {
                return {
                    language: String,
                    todayDate: String,
                    inventoryCode: String,
                    orderNumber: Number,
                    weekOptime: Number,
                    orderItems: Object,
                    factoryPerformance: Object,
                    factoryOperation: Object,
                    factoryInventory: Object,
                    factoryOrderIndex: Object,
                    orderProductPart: Object,
                    productSKU: Number,
                    actualQuantity: Number,
                    optimalQuantity: Object,
                    selectProduct: Object,
                    selectCustomer: Object,
                    operationTime: Number,
                    inventoryItems: Object,
                    factoryProfileModel: String,
                    materialCount: Boolean
                }
            }

            static get observers() {
                return [
                    'getOrderNumber(factoryOrderIndex.order_count)',
                    'getOperationTime(factoryOperation.op_end, factoryOperation.op_start, factoryOperation.op_day)',
                    'isOptimizeModeEnabled(factoryPerformance.optimize)',
                    'setProductInventory(selectProduct.inventory_code)'
                ]
            }

            ready() {
                super.ready();
                this._initialDatePicker();
                this._setOrderDatePosition();
            }

            connectedCallback() {
                super.connectedCallback()
                this.loadResources(this.resolveUrl('../../data/locales.json'))
            }

            isOptimizeModeEnabled(optimizeMode) {
                if (optimizeMode === 'increase-profit' || optimizeMode === 'reduce-cost') {
                    this.$.optimizeData.hidden = false;
                    this.$.optimizeDataSeparate.hidden = false;
                } else {
                    this.$.optimizeData.hidden = true;
                    this.$.optimizeDataSeparate.hidden = true;
                }
            }

            getProductImage(url) {
                return ((url) ? url : this.rootPath + 'images/product/default.svg')
            }

            getOptimalQuantity(cost, part) {
                if (!cost || !part) return
                const optimizeRule = this.factoryPerformance.optimize
                const selectInventory = this.factoryInventory
                const cycleTimePerItem = this.getCycleTimePerItem(part)
                if (selectInventory) {
                    if (optimizeRule === 'increase-profit' && this.selectProduct.inventory_use && this.selectProduct
                        .cost && cycleTimePerItem) {
                        let i = 0;
                        let maxMaterial = 0;
                        for (i in selectInventory) {
                            maxMaterial = selectInventory[i].quantity
                        }
                        let model = {
                            "optimize": "profit",
                            "opType": "max",
                            "constraints": {
                                "material": {
                                    "max": maxMaterial
                                },
                                "time": {
                                    "max": this.weekOptime
                                }
                            },
                            "variables": {
                                "product": {
                                    "material": this.selectProduct.inventory_use,
                                    "time": cycleTimePerItem,
                                    "profit": this.selectProduct.cost,
                                    "product": 1
                                }
                            },
                            "ints": {
                                "product": 1
                            }
                        }
                        this.optimalQuantity = solver.Solve(model).product;
                        console.log(solver.Solve(model));
                    }
                }
                return this.optimalQuantity || 0
            }

            getOperationTime(end, start, opday) {
                if (!end || !start || !opday) return;
                const endtime = end.replace(/\:/g, '.');
                const starttime = start.replace(/\:/g, '.');
                const opTime = endtime - starttime;
                const opDay = opday.split(',').length
                this.operationTime = opTime * 3600;
                const weekOptime = this.weekOptime = opTime * opDay; // set to global variable
                return weekOptime;
            }

            getOrderNumber(order) {
                if (order === 0) {
                    this.orderNumber = 1;
                    return 1
                } else {
                    this.orderNumber = order // start index is 0 
                    return order
                }
            }

            getActualQuantity(amount) {
                if (!amount) return;
                const accept_waste = this.factoryPerformance.aw;
                const actual_quantity = Math.ceil((amount / (1 - accept_waste)));
                this.actualQuantity = actual_quantity;
                return actual_quantity;
            }

            getSumProductTime(part, amount) {
                if (!part || !amount) return;
                let productCycleArr = []
                let productSetupArr = []
                productCycleArr = part.map(part => part.cycle); // returns a new array of part cycle iterated
                productSetupArr = part.map(part => part.setup); // returns a new array of part setup iterated
                const flatCycleArr = productCycleArr.reduce((prev, cur) => [...prev, ...cur]) // flat subarr to arr
                const flatSetupArr = productSetupArr.reduce((prev, cur) => [...prev, ...cur]) // flat subarr to arr
                const sumCycle = flatCycleArr.reduce((a, b) => a + b); // apply sum function to all arr items to get sumCycle
                const sumSetup = flatSetupArr.reduce((a, b) => a + b); // apply sum function to all arr items to get sumSetup
                const sumDuration = (sumSetup + (sumCycle * this.getActualQuantity(amount))); // sumCycle * quantity
                this.orderDuration = sumDuration;
                return this._durationToStr(sumDuration); // convert to hr min sec
            }

            getProductCost(cost, amount) {
                if (!cost || !amount) return;
                const actual_amount = this.getActualQuantity(amount);
                const total_cost = (cost * actual_amount);
                return total_cost;
            }

            getProductProcessSequence(arr) {
                if (!arr) return;
                return arr.join(' → ');
            }

            getSumSetupTime(setup) {
                if (!setup) return;
                let sumSetupTime = setup.reduce((a, b) => a + b); // apply sum function to all arr items to get sumSetup
                return sumSetupTime.toFixed(1);
            }

            getSumCycleTime(cycle) {
                if (!cycle) return;
                let sumCycleTime = cycle.reduce((a, b) => a + b); // apply sum function to all arr items to get sumCycle
                return sumCycleTime.toFixed(1);
            }

            getRandomColor() {
                const color = Math.floor(0x1000000 * Math.random()).toString(16);
                return '#' + ('000000' + color).slice(-6);
            }

            getDateTime() {
                const now = new Date();
                let year = now.getFullYear();
                let month = now.getMonth() + 1;
                let day = now.getDate();
                let hour = now.getHours();
                let minute = now.getMinutes();
                let second = now.getSeconds();
                if (month.toString().length == 1) {
                    month = '0' + month;
                }
                if (day.toString().length == 1) {
                    day = '0' + day;
                }
                if (hour.toString().length == 1) {
                    hour = '0' + hour;
                }
                if (minute.toString().length == 1) {
                    minute = '0' + minute;
                }
                if (second.toString().length == 1) {
                    second = '0' + second;
                }
                let dateTime = year + '-' + month + '-' + day + '_' + hour + '-' + minute + '-' + second;
                return dateTime;
            }

            getCycleTimePerItem(part) {
                if (!part) return;
                let productCycleArr = []
                productCycleArr = part.map(part => part.cycle);
                const flatCycleArr = productCycleArr.reduce((prev, cur) => [...prev, ...cur])
                const sumCycle = flatCycleArr.reduce((a, b) => a + b);
                return sumCycle / 60;
            }

            getUseInventory(amount, material) {
                if (!amount || !material) return;
                return (this.getActualQuantity(amount) * material);
            }

            setProductPart(product) {
                if (!product) return;
                this.orderProductPart = product.part; // set to global variable
                return product.name;
            }

            setProductSKU(sku) {
                if (!sku) return;
                this.productSKU = sku; // set to global variable
                return sku;
            }

            setProductInventory(inventoryCode) {
                if (inventoryCode) {
                    this.inventoryCode = inventoryCode
                } else {
                    this.inventoryCode = ""
                }
            }

            // CONVERT TIME TO STRING
            _durationToStr(sec) {
                sec = Number(sec);
                let sign = '';
                let hours = this._leftPad(Math.floor(Math.abs(sec) / 3600));
                let minutes = this._leftPad(Math.round(Math.abs(sec) % 3600 / 60));
                let seconds = this._leftPad(Math.round(Math.abs(sec) % 3600 % 60));
                return hours + 'hrs ' + minutes + 'mins ' + seconds + 'sec';
            }

            // ADD 0 to numbers less than 10,Eg: 2 -> 02 
            _leftPad(number) {
                return ((number < 10 && number >= 0) ? '0' : '') + number;
            }

            _setOrderDatePosition() {
                const today = new Date();
                let dd = today.getDate()
                let mm = today.getMonth() + 1
                let yyyy = today.getFullYear()
                if (dd < 10) {
                    dd = '0' + dd
                }
                if (mm < 10) {
                    mm = '0' + mm
                }
                this.todayDate = yyyy + '-' + mm + '-' + dd
            }

            // SETUP CALENDAR DATE PICKER FORMAT
            _initialDatePicker() {
                let datepicker = this.$.deliverySelector;
                datepicker.addEventListener('value-changed', function () {
                    this.orderDelivery  = (new Date(datepicker.value).getTime() / 1000);
                });
            }

            // CLEAR INPUT FORM FIELD
            _clearField() {
                this.$.customerSelector.value = "";
                this.$.productSelector.value = "";
                this.$.orderQuantity.value = 1;
                this.$.deliverySelector.value = "";
            }

            // PRINT ORDER REPORT
            printOrderReport(e) {
                this.dispatchEvent(new CustomEvent('closedrawer', {
                    detail: {
                        kicked: true,
                        composed: true
                    }
                }));
                document.title = 'order_' + this.getDateTime();
                window.print();
                return
            }

            // Verify that selected product is 
            verifyProductPart() {
                const model = this.factoryProfileModel;
                const partLength = this.$.productSelector.selectedItem.part.length;
                if (((model === "parallel" || model === "serial") && partLength > 1) || (model === "multi" &&
                        partLength === 1)) {
                    window.alert(
                        `Forbidden! You cannot manufacture this product with ${model} production model. Please select multi-component model`
                    )
                    this._clearField();
                    return
                }
            }

            // CREATE ORDER
            createOrder() {
                const orderNo = this.orderNumber
                const orderCustomerName = this.$.customerSelector.value
                const timestamp = Math.round(new Date().getTime() / 1000.0)
                const orderProductName = this.$.productSelector.value
                const orderProductDescription = this.$.productSelector.selectedItem.description
                const orderProductPart = this.$.productSelector.selectedItem.part
                const orderProductSKU = this.$.productSelector.selectedItem.sku
                const orderQuantity = this.getActualQuantity(this.$.orderQuantity.value)
                const orderDuration = this.orderDuration
                const orderDelivery = (new Date(this.$.deliverySelector.value).getTime() / 1000)
                const orderColor = this.getRandomColor()
                const productColor = this.$.productSelector.selectedItem.color
                const inventoryUse = this.$.productSelector.selectedItem.inventory_use
                const inventoryCode = this.$.productSelector.selectedItem.inventory_code
                const inventoryRequired = this.getUseInventory(this.$.orderQuantity.value, inventoryUse)

                if (this.$.orderQuantity.value === 0) {
                    window.alert("Order product quantity cannot be 0")
                    return;
                }
                if (orderNo !== "" && orderCustomerName !== "" && orderProductName !== "" && orderProductPart !==
                    "" && orderProductSKU !== "" && orderQuantity !== "" && !(isNaN(
                        orderDelivery))) {

                    this.$.orderQuery.ref.push({
                        order_date: timestamp,
                        order_no: orderNo,
                        order_customer: orderCustomerName,
                        order_product_name: orderProductName,
                        order_product_description: orderProductDescription,
                        order_product_part: orderProductPart,
                        order_product_sku: orderProductSKU,
                        order_quantity: orderQuantity,
                        order_duration: orderDuration,
                        order_delivery: orderDelivery,
                        order_status: "waiting",
                        order_color: orderColor
                    });
                    this.$.historyQuery.ref.push({
                        order_date: timestamp,
                        order_delivery: orderDelivery,
                        order_no: orderNo,
                        order_customer: orderCustomerName,
                        order_product: orderProductName,
                        order_quantity: orderQuantity,
                        product_color: productColor
                    });
                    this._pushNotification(`Create order no. ${orderNo}`, 'normal')
                    this._updateOrderIndex(orderNo)
                    if (this.materialCount) {
                        this._updateMaterialInventory(inventoryRequired, inventoryCode)
                    }
                    window.alert("Added to production schedule successfully");
                    this._clearField();
                } else {
                    window.alert("Input field cannot be blank, please fill in completely.");
                }
            }

            _updateMaterialInventory(inventoryRequired, inventoryCode) {
                if (!inventoryRequired || !inventoryCode) return
                const query = this.$.inventoryQuery.ref;
                query.orderByChild("code").equalTo(inventoryCode).once("value", (snapshot) => {
                    if (snapshot.val()) {
                        const key = Object.keys(snapshot.val())
                        const original = Object.values(snapshot.val()).map(x => x.quantity)
                        const remain = original - inventoryRequired

                        if (original < inventoryRequired) {
                            window.alert(`Raw material code ${inventoryCode} is out of stock.`)
                            snapshot.ref.child("/" + key).update({
                                quantity: 0
                            })
                            this._pushNotification(`Inventory code ${inventoryCode} is out of stock`,
                                'critical')
                        } else {
                            snapshot.ref.child("/" + key).update({
                                quantity: remain
                            })
                        }
                    }
                });
            }

            _updateOrderIndex(previous) {
                this.$.factoryOrderIndex.ref.set({
                    order_count: previous + 1
                });
                this.orderNumber = this.factoryOrderIndex.order_count;
            }

            _pushNotification(detail, type) {
                this.$.notificationQuery.ref.push({
                    created: Math.round(new Date().getTime() / 1000.0),
                    detail: detail,
                    type: type
                });
            }

        }
        customElements.define(ViewPlanOrder.is, ViewPlanOrder)
    </script>
</dom-module>